package org.tokaf.datasearcher;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.NoSuchElementException;
import java.util.Vector;

import org.openrdf.model.Resource;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.model.impl.BNodeImpl;
import org.openrdf.model.impl.GraphImpl;
import org.openrdf.model.impl.LiteralImpl;
import org.openrdf.model.impl.URIImpl;
import org.openrdf.sesame.config.AccessDeniedException;
import org.openrdf.sesame.constants.QueryLanguage;
import org.openrdf.sesame.query.MalformedQueryException;
import org.openrdf.sesame.query.QueryEvaluationException;
import org.openrdf.sesame.query.QueryResultsTable;
import org.openrdf.sesame.repository.SesameRepository;
import org.tokaf.MyVectorCompare;
import org.tokaf.normalizer.Normalizer;
import org.tokaf.normalizer.SimpleNormalizer;

/**
 * <p>Base class for all class working with Sesame. Its subclasses must
 * override initSource method.</p> <p>Copyright (c) 2006</p>
 * @author Alan Eckhardt
 * @version 1.0
 */
public abstract class SesameSearcher extends DataSearcher implements
		DataModifier {
	public SesameSearcher() {
	}

	public SesameSearcher(String db, String query, Normalizer norm)
			throws Exception {
		initSource(db);
		initSearch(query);
		this.norm = norm;
	}

	public boolean needsSort() {
		return true;
	}

	public SimpleNormalizer getDefaultNormalizer() {
		return new SimpleNormalizer();
	}

	QueryResultsTable table;

	public abstract int initSource(String db);

	public int initSource(DataSearcher searcher) {

		long startTime = System.nanoTime();
		if (searcher instanceof SesameFileSearcher) {
			myRepository = ((SesameFileSearcher) searcher).myRepository;

			initSourceTime = System.nanoTime() - startTime;
			return 1;
		}
		if (searcher instanceof SesameRepositorySearcher) {
			myRepository = ((SesameRepositorySearcher) searcher).myRepository;
			initSourceTime = System.nanoTime() - startTime;
			return 1;
		}
		initSourceTime = System.nanoTime() - startTime;
		return -1;
	}

	protected SesameRepository myRepository;

	protected ArrayList results;

	protected int columnCount = -1;

	protected int index = -1;

	protected int searchIndex = -1;

	protected String query = null;

	public int deleteTriple(Object subject, Object predicate, Object object) {
		GraphImpl g = new GraphImpl();

		if (subject instanceof String) {
			Resource subjTemp = new URIImpl((String) subject);
			subject = subjTemp;
		}
		if (predicate instanceof String) {
			URIImpl predTemp = new URIImpl((String) predicate);
			predicate = predTemp;
		}
		if (!(object instanceof Value)) {
			try {
				URIImpl objTemp = new URIImpl(object.toString());
				object = objTemp;
			} catch (java.lang.IllegalArgumentException ex) {
				LiteralImpl objTemp = new LiteralImpl(object.toString());
				object = objTemp;
			}
		}
		g.add((org.openrdf.model.Resource) subject, (URI) predicate,
				(Value) object);
		try {
			myRepository.removeGraph(g);
			// removeGraph
		} catch (IOException e) {
			e.printStackTrace();
			return -1;
		} catch (AccessDeniedException e) {
			e.printStackTrace();
			return -2;
		} catch (Exception e) {
			e.printStackTrace();
			return -2;
		}
		return 1;

	}

	public int deleteTriple(Object subject, Object predicate, Object object,
			String dataType) {
		GraphImpl g = new GraphImpl();
		if (subject instanceof String) {
			Resource subjTemp = new URIImpl((String) subject);
			subject = subjTemp;
		}
		if (predicate instanceof String) {
			URIImpl predTemp = new URIImpl((String) predicate);
			predicate = predTemp;
		}
		LiteralImpl objTemp = new LiteralImpl(object.toString(), new URIImpl(
				dataType));
		object = objTemp;
		g.add((Resource) subject, (URI) predicate, (Value) object);
		try {
			myRepository.removeGraph(g);
			// removeGraph
		} catch (IOException e) {
			e.printStackTrace();
			return -1;
		} catch (AccessDeniedException e) {
			e.printStackTrace();
			return -2;
		} catch (Exception e) {
			e.printStackTrace();
			return -2;
		}
		return 1;

	}

	public int addTriple(Object subject, Object predicate, Object object) {
		GraphImpl g = new GraphImpl();
		if (subject instanceof String) {
			Resource subjTemp = new URIImpl((String) subject);
			subject = subjTemp;
		}
		if (predicate instanceof String) {
			URIImpl predTemp = new URIImpl((String) predicate);
			predicate = predTemp;
		}
		if (object instanceof String) {
			try {
				URIImpl objTemp = new URIImpl((String) object);
				object = objTemp;
			} catch (java.lang.IllegalArgumentException ex) {
				LiteralImpl objTemp = new LiteralImpl((String) object);
				object = objTemp;
			}
		}
		g.add((Resource) subject, (URI) predicate, (Value) object);
		try {
			myRepository.addGraph(g);
		} catch (IOException e) {
			e.printStackTrace();
			return -1;
		} catch (AccessDeniedException e) {
			e.printStackTrace();
			return -2;
		}
		return 1;

	}

	public int addTriple(Object subject, Object predicate, Object object,
			String dataType) {
		GraphImpl g = new GraphImpl();
		if (subject instanceof String) {
			Resource subjTemp = new URIImpl((String) subject);
			subject = subjTemp;
		}
		if (predicate instanceof String) {
			URIImpl predTemp = new URIImpl((String) predicate);
			predicate = predTemp;
		}
		LiteralImpl objTemp;
		try {
			objTemp = new LiteralImpl(object.toString(), new URIImpl(dataType));
		} catch (Exception ex) {
			objTemp = new LiteralImpl(object.toString());
		}
		object = objTemp;
		g.add((Resource) subject, (URI) predicate, (Value) object);
		try {
			myRepository.addGraph(g);
		} catch (IOException e) {
			e.printStackTrace();
			return -1;
		} catch (AccessDeniedException e) {
			e.printStackTrace();
			return -2;
		}
		return 1;

	}

	public int addReifiedTriple(Object subject, Object predicate,
			Object object, Object reifPredicate, Object reifObject) {
		GraphImpl g = new GraphImpl();
		if (subject instanceof String) {
			Resource subjTemp = new URIImpl((String) subject);
			subject = subjTemp;
		}
		if (predicate instanceof String) {
			URIImpl predTemp = new URIImpl((String) predicate);
			predicate = predTemp;
		}
		if (object instanceof String) {
			try {
				URIImpl objTemp = new URIImpl((String) object);
				object = objTemp;
			} catch (java.lang.IllegalArgumentException ex) {
				LiteralImpl objTemp = new LiteralImpl((String) object);
				object = objTemp;
			}
		}

		if (reifPredicate instanceof String) {
			URIImpl predTemp = new URIImpl((String) reifPredicate);
			reifPredicate = predTemp;
		}
		if (reifObject instanceof String) {
			try {
				URIImpl objTemp = new URIImpl((String) reifObject);
				reifObject = objTemp;
			} catch (java.lang.IllegalArgumentException ex) {
				LiteralImpl objTemp = new LiteralImpl((String) reifObject);
				reifObject = objTemp;
			}
		}
		String bnName = ((URI) ((Resource) subject)).getLocalName() + "_"
				+ ((URI) predicate).getLocalName() + "_"
				+ ((Value) object).toString();
		bnName = bnName.replace(".", "_");
		BNodeImpl bn = new BNodeImpl(bnName);
		String rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
		g.add(bn, new URIImpl(rdf + "type"), new URIImpl(rdf + "Statement"));
		g.add(bn, new URIImpl(rdf + "subject"), (Resource) subject);
		g.add(bn, new URIImpl(rdf + "predicate"), (URI) predicate);
		g.add(bn, new URIImpl(rdf + "object"), (Value) object);
		g.add(bn, (URI) reifPredicate, (Value) reifObject);
		try {
			myRepository.addGraph(g);
		} catch (IOException e) {
			e.printStackTrace();
			return -1;
		} catch (AccessDeniedException e) {
			e.printStackTrace();
			return -2;
		}
		return 1;
	}

	public int addReifiedTriple(Object subject, Object predicate,
			Object object, String datatype, Object reifPredicate,
			Object reifObject, String reifDatatype) {
		GraphImpl g = new GraphImpl();
		if (subject instanceof String) {
			Resource subjTemp = new URIImpl((String) subject);
			subject = subjTemp;
		}
		if (predicate instanceof String) {
			URIImpl predTemp = new URIImpl((String) predicate);
			predicate = predTemp;
		}
		if (object instanceof String) {
			LiteralImpl objTemp = new LiteralImpl((String) object, new URIImpl(
					datatype));
			object = objTemp;
		}

		if (reifPredicate instanceof String) {
			URIImpl predTemp = new URIImpl((String) reifPredicate);
			reifPredicate = predTemp;
		}
		if (reifObject instanceof String) {
			LiteralImpl objTemp = new LiteralImpl((String) reifObject,
					new URIImpl(reifDatatype));
			reifObject = objTemp;
		}
		String bnName = ((URI) ((Resource) subject)).getLocalName() + "_"
				+ ((URI) predicate).getLocalName() + "_"
				+ ((Value) object).toString();
		bnName = bnName.replace(".", "_");
		BNodeImpl bn = new BNodeImpl(bnName);
		String rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
		g.add(bn, new URIImpl(rdf + "type"), new URIImpl(rdf + "Statement"));
		g.add(bn, new URIImpl(rdf + "subject"), (Resource) subject);
		g.add(bn, new URIImpl(rdf + "predicate"), (URI) predicate);
		g.add(bn, new URIImpl(rdf + "object"), (Value) object);
		g.add(bn, (URI) reifPredicate, (Value) reifObject);
		try {
			myRepository.addGraph(g);
		} catch (IOException e) {
			e.printStackTrace();
			return -1;
		} catch (AccessDeniedException e) {
			e.printStackTrace();
			return -2;
		}
		return 1;
	}

	public int addReifiedTriple(Object subject, Object predicate,
			Object object, Object reifPredicate, Object reifObject,
			String reifDatatype) {
		GraphImpl g = new GraphImpl();
		if (subject instanceof String) {
			Resource subjTemp = new URIImpl((String) subject);
			subject = subjTemp;
		}
		if (predicate instanceof String) {
			URIImpl predTemp = new URIImpl((String) predicate);
			predicate = predTemp;
		}
		if (object instanceof String) {
			try {
				URIImpl objTemp = new URIImpl((String) object);
				object = objTemp;
			} catch (java.lang.IllegalArgumentException ex) {
				LiteralImpl objTemp = new LiteralImpl((String) object);
				object = objTemp;
			}
		}

		if (reifPredicate instanceof String) {
			URIImpl predTemp = new URIImpl((String) reifPredicate);
			reifPredicate = predTemp;
		}
		if (reifObject instanceof String) {
			LiteralImpl objTemp = new LiteralImpl((String) reifObject,
					new URIImpl(reifDatatype));
			reifObject = objTemp;
		}
		String bnName = ((URI) ((Resource) subject)).getLocalName() + "_"
				+ ((URI) predicate).getLocalName() + "_"
				+ ((Value) object).toString();
		bnName = bnName.replace(".", "_");
		BNodeImpl bn = new BNodeImpl(bnName);
		String rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
		g.add(bn, new URIImpl(rdf + "type"), new URIImpl(rdf + "Statement"));
		g.add(bn, new URIImpl(rdf + "subject"), (Resource) subject);
		g.add(bn, new URIImpl(rdf + "predicate"), (URI) predicate);
		g.add(bn, new URIImpl(rdf + "object"), (Value) object);
		g.add(bn, (URI) reifPredicate, (Value) reifObject);
		try {
			myRepository.addGraph(g);
		} catch (IOException e) {
			e.printStackTrace();
			return -1;
		} catch (AccessDeniedException e) {
			e.printStackTrace();
			return -2;
		}
		return 1;
	}

	public int addReifiedTriple(Object subject, Object predicate,
			Object object, String datatype, Object reifPredicate,
			Object reifObject) {
		GraphImpl g = new GraphImpl();
		if (subject instanceof String) {
			Resource subjTemp = new URIImpl((String) subject);
			subject = subjTemp;
		}
		if (predicate instanceof String) {
			URIImpl predTemp = new URIImpl((String) predicate);
			predicate = predTemp;
		}
		if (object instanceof String) {
			LiteralImpl objTemp = new LiteralImpl((String) object, new URIImpl(
					datatype));
			object = objTemp;
		}
		if (reifPredicate instanceof String) {
			URIImpl predTemp = new URIImpl((String) reifPredicate);
			reifPredicate = predTemp;
		}
		if (reifObject instanceof String) {
			try {
				URIImpl objTemp = new URIImpl((String) reifObject);
				reifObject = objTemp;
			} catch (java.lang.IllegalArgumentException ex) {
				LiteralImpl objTemp = new LiteralImpl((String) reifObject);
				reifObject = objTemp;
			}
		}

		String bnName = ((URI) ((Resource) subject)).getLocalName() + "_"
				+ ((URI) predicate).getLocalName() + "_"
				+ ((Value) object).toString();
		bnName = bnName.replace(".", "_");
		BNodeImpl bn = new BNodeImpl(bnName);
		String rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
		g.add(bn, new URIImpl(rdf + "type"), new URIImpl(rdf + "Statement"));
		g.add(bn, new URIImpl(rdf + "subject"), (Resource) subject);
		g.add(bn, new URIImpl(rdf + "predicate"), (URI) predicate);
		g.add(bn, new URIImpl(rdf + "object"), (Value) object);
		g.add(bn, (URI) reifPredicate, (Value) reifObject);
		try {
			myRepository.addGraph(g);
		} catch (IOException e) {
			e.printStackTrace();
			return -1;
		} catch (AccessDeniedException e) {
			e.printStackTrace();
			return -2;
		}
		return 1;
	}

	public void sort(int index) {
		if (results == null)
			return;
		long startTime = System.nanoTime();
		MyVectorCompare comp = new MyVectorCompare(index, norm);
		Collections.sort(results, comp);
		initSearchTime += System.nanoTime() - startTime;
	}

	protected Object getField(int row, int column) {
		try {
			if (row < 0 || row >= results.size() || column >= columnCount
					|| column < 0)
				return null;
			// return res[row][column];
			// return table.getValue(row,column);

			Vector v = (Vector) results.get(row);
			return v.get(column);
		} catch (IndexOutOfBoundsException ex) {
			System.out.println("" + query + "\n");
			System.out.println("" + row + "\n");
			System.out.println("" + column + "\n");
		}
		return null;
	}

	public Object getField(int column) {
		if (index < 0 || column > columnCount)
			return null;
		return getField(index, column);

	}

	public Object findObject(Object obj, int position, int index) {

		if (position == index) {
			return obj;
		}
		if (index == 1) {
			return name;
		}

		if (position == 0) {
			String queryString = "select X,<"
					+ name
					+ "> ,Y from {X} <"
					+ name
					+ "> {Y} "
					+ "  where X like \"*"
					+ obj.toString()
					+ "*\""
					+ "	using namespace rdf  =<http://www.w3.org/1999/02/22-rdf-syntax-ns#>, "
					+ "	rdfs  =<http://www.w3.org/2000/01/rdf-schema#> ";
			queryString = "select Y from {<" + obj.toString() + ">} <" + name
					+ "> {Y} ";
			QueryResultsTable resultsTemp;
			try {
				resultsTemp = myRepository.performTableQuery(
						QueryLanguage.SERQL, queryString);
				// Graph g=myRepository.performGraphQuery(QueryLanguage.SERQL,
				// queryString);
				// StatementIterator i=g.getStatements();
				// if(i.hasNext()){
				// Statement s= i.next();
				// return s.getObject();
				// }
			} catch (Exception e) {
				e.printStackTrace();
				return null;
			}
			return resultsTemp.getValue(0, 0);
		}

		return null;
		/*
		 * if (searchIndex > -1 && ((Vector)
		 * results.get(searchIndex)).get(position) .equals(obj)) return
		 * getField(searchIndex, index); for ( searchIndex = 0; searchIndex <
		 * results.size(); searchIndex++) if (getField(searchIndex,
		 * position).equals(obj)) return getField(searchIndex, index);
		 * searchIndex=0; return null;
		 */
	}

	public int advance() {
		if (results == null || index < 0 || results.size() <= index + 1) {
			index++;
			return -1;
		}
		index++;
		return index;
	}

	public int getPosistion() {
		if (results == null || index < 0)
			return -1;
		return index;
	}

	public void initSearch(String query) {
		initSearch(query, QueryLanguage.SERQL);
	}

	public void initSearch(String query, QueryLanguage lang) {
		long startTime = System.nanoTime();
		this.query = query;
		try {
			table = myRepository.performTableQuery(lang, query);
		} catch (IOException e) {
			System.out.println(query);
			e.printStackTrace();
		} catch (MalformedQueryException e) {
			System.out.println(query);
			e.printStackTrace();
		} catch (QueryEvaluationException e) {
			System.out.println(query);
			e.printStackTrace();
		} catch (AccessDeniedException e) {
			System.out.println(query);
			e.printStackTrace();
		}

		results = new ArrayList(table.getRowCount());
		columnCount = table.getColumnCount();
		for (int i = 0; i < table.getRowCount(); i++) {
			Vector v = new Vector(columnCount);
			for (int j = 0; j < table.getColumnCount(); j++)
				v.add(table.getValue(i, j));
			results.add(v);
		}
		initSearchTime += System.nanoTime() - startTime;
		if (results != null && results.size() > 0)
			index = 0;
	}

	public boolean hasNext() {
		if (results == null || index == -1 || index >= results.size())
			return false;
		return true;
	}

	public Object getFieldAtPosition(int index, int position) {
		return getField(index, position);
	}

	public Object next() {
		if (index < 0 || index >= results.size())
			throw new NoSuchElementException();
		Vector v = (Vector) results.get(index);
		index++;
		return v;
	}

	public void resetSearch() {
		if (index != -1)
			index = 0;
	}

}
